#include <UI/UIObject.h>
#include <UI/UIWindow.h>
#include <UI/UIManager.h>

namespace ne
{
    UIObject::UIObject(const std::string &name)
        : Node(),
          RenderableObject(name),
          mID(0),
          mWidth(32.0f), mHeight(32.0f),
          mColor(UI_COLOR_WHITE),
          mAlignType(TAT_BOTTOM_LEFT),
          mSpriteName(),
          mMouseOver(false),
          mMouseButtonsDown(0)
    {
    }

    UIWindow* UIObject::getWindow() const
    {
        return dynamic_cast<UIWindow*>(getRoot());
    }

    void UIObject::setID(uint32_t id)
    {
        mID = id;
    }

    uint32_t UIObject::getID() const
    {
        return mID;
    }

    // Size
    void UIObject::setSize(const Vector2 &v)
    {
        setSize(v.x, v.y);
    }

    Vector2 UIObject::getSize() const
    {
        return Vector2(mWidth, mHeight);
    }

    void UIObject::setSize(const real width, const real height)
    {
        if (mWidth != width ||
            mHeight != height)
        {
            mWidth = width;
            mHeight = height;
            _onResized(Vector2(mWidth, mHeight));
        }
    }

    void UIObject::getSize(real &width, real &height) const
    {
        width = mWidth;
        height = mHeight;
    }

    void UIObject::setWidth(const real width)
    {
        if (mWidth != width)
        {
            mWidth = width;
            _onResized(Vector2(mWidth, mHeight));
        }
    }

    real UIObject::getWidth() const
    {
        return mWidth;
    }

    void UIObject::setHeight(const real height)
    {
        if (mHeight != height)
        {
            mHeight = height;
            _onResized(Vector2(mWidth, mHeight));
        }
    }

    real UIObject::getHeight() const
    {
        return mHeight;
    }

    // Color
    void UIObject::setColor(const Color &color)
    {
        mColor = color;
    }

    Color UIObject::getColor() const
    {
        if (mMouseOver)
        {
            return mColor * UI_COLOR_HIGH_LIGHT;
        }
        return mColor;
    }

    void UIObject::setAlpha(const real alpha)
    {
        mColor.a = alpha;
    }

    real UIObject::getAlpha() const
    {
        return mColor.a;
    }

    void UIObject::setAlignType(const UIAlignType align)
    {
        mAlignType = align;
        needUpdate();
    }

    UIAlignType UIObject::getAlignType() const
    {
        return mAlignType;
    }

    const Vector3& UIObject::getAlignPosition() const
    {
        _updateFromParent();
        return mAlignPosition;
    }

    void UIObject::setSprite(const std::string &name)
    {
        mSpriteName = name;
    }

    const std::string& UIObject::getSprite() const
    {
        return mSpriteName;
    }

    // Enable
    void UIObject::setEnable(const bool b)
    {
        if (b != isEnable())
        {
            RenderableObject::setEnable(b);
            if (isEnable())
            {
                _onEnabled();
            }
            else
            {
                _onDisabled();
            }
        }
    }

    void UIObject::setEnableRecursively(const bool b)
    {
        setEnable(b);
        if (b)
        {
            for (NodeSetIterator it=mChildren.begin(); it!=mChildren.end(); ++it)
            {
                UIObject *child = dynamic_cast<UIObject*>(*it);
                child->setEnableRecursively(b);
            }
        }
    }

    // Visible
    void UIObject::setVisible(const bool b)
    {
        if (b != isVisible())
        {
            RenderableObject::setVisible(b);
            if (isVisible())
            {
                _onShown();
            }
            else
            {
                _onHidden();
            }
        }
    }

    void UIObject::setVisibleRecursively(const bool b)
    {
        setVisible(b);
        if (b)
        {
            for (NodeSetIterator it=mChildren.begin(); it!=mChildren.end(); ++it)
            {
                UIObject *child = dynamic_cast<UIObject*>(*it);
                child->setVisibleRecursively(b);
            }
        }
    }

    // Active
    void UIObject::setActive(const bool b)
    {
        if (b != isActive())
        {
            RenderableObject::setActive(b);
            if (isActive())
            {
                _onActived();
            }
            else
            {
                _onDeactived();
            }
        }
    }

    void UIObject::setActiveRecursively(const bool b)
    {
        setActive(b);
        if (b)
        {
            for (NodeSetIterator it=mChildren.begin(); it!=mChildren.end(); ++it)
            {
                UIObject *child = dynamic_cast<UIObject*>(*it);
                child->setActiveRecursively(b);
            }
        }
    }

    bool UIObject::isMouseOver() const
    {
        return mMouseOver;
    }

    bool UIObject::isMouseButtonDown(const MouseButton button) const
    {
        return (mMouseButtonsDown & button);
    }

    UIObject::~UIObject()
    {
    }

    void UIObject::_updateFromParent(const bool parentHasChanged) const
    {
        if (mNeedUpdate || parentHasChanged)
        {
            Node::_updateFromParent(parentHasChanged);
            _updateAlignPosition();
        }
    }

    void UIObject::_updateAlignPosition() const
    {
        mAlignPosition = getPosition(TS_WORLD);
        Vector3 xAxis = getXAxis();
        Vector3 yAxis = getYAxis();
        UIAlignType align = getAlignType();
        switch (align)
        {
            case TAT_BOTTOM_LEFT: break;

            case TAT_BOTTOM:
            {
                mAlignPosition -= xAxis * getWidth() * 0.5f;
                break;
            }

            case TAT_BOTTOM_RIGHT:
            {
                mAlignPosition -= xAxis * getWidth();
                break;
            }

            case TAT_LEFT:
            {
                mAlignPosition -= yAxis * getHeight() * 0.5f;
                break;
            }

            case TAT_CENTER:
            {
                mAlignPosition -= xAxis * getWidth() * 0.5f + yAxis * getHeight() * 0.5f;
                break;
            }

            case TAT_RIGHT:
            {
                mAlignPosition -= xAxis * getWidth() + yAxis * getHeight() * 0.5f;
                break;
            }

            case TAT_TOP_LEFT:
            {
                mAlignPosition -= yAxis * getHeight();
                break;
            }

            case TAT_TOP:
            {
                mAlignPosition -= xAxis * getWidth() * 0.5f + yAxis * getHeight();
                break;
            }

            case TAT_TOP_RIGHT:
            {
                mAlignPosition -= xAxis * getWidth() + yAxis * getHeight();
                break;
            }

            default: break;
        }
    }

    // FIXME:
    bool UIObject::_updateSelf()
    {
        if (isEnable())
        {
            return true;
        }
        return false;
    }

    bool UIObject::_updateAll()
    {
        if (_updateSelf())
        {
            for (NodeSetIterator it=mChildren.begin(); it!=mChildren.end(); ++it)
            {
                UIObject *child = dynamic_cast<UIObject*>(*it);
                child->_updateAll();
            }
            return true;
        }
        return false;
    }

    bool UIObject::_renderSelf()
    {
        if (isVisible())
        {
            UIWindow *pWindow = getWindow();
            if (pWindow)
            {
                _genAtlasGeometry(pWindow->getAtlasGeometry(), pWindow->getAtlas());
            }
            return true;
        }
        return false;
    }

    bool UIObject::_renderAll()
    {
        if (_renderSelf())
        {
            for (NodeSetIterator it=mChildren.begin(); it!=mChildren.end(); ++it)
            {
                UIObject *child = dynamic_cast<UIObject*>(*it);
                child->_renderAll();
            }
            return true;
        }
        return false;
    }

    void UIObject::_genAtlasGeometry(const DynamicGeometryPtr &pGeometry, const AtlasPtr &pAtlas)
    {
        if (pGeometry.notNull() && pAtlas.notNull())
        {
            const std::string &sprite = getSprite();
            if (!sprite.empty())
            {
                pAtlas->genSpriteGeometry(sprite, pGeometry,
                                          getAlignPosition(),
                                          getXAxis(), getYAxis(),
                                          getSize(), getColor());
            }
        }
    }

    // FIXME: Need to test
    UIObject* UIObject::_detected(const Ray &ray)
    {
        if (isEnable())
        {
            mMouseOver = false;
            Vector3 pos = getAlignPosition();
            Vector3 normal = getBack();
            Plane plane(normal, -pos.dotProduct(normal));
            real t = -1.0f;
            if (ray.trace(plane, t))
            {
                Vector3 hit = ray.getPoint(t);
                Vector3 vHit = hit - pos;
                Vector3 vPro = convertWorldToLocalVector(vHit);
                if (0.0f <= vPro.x && vPro.x <= getWidth() &&
                    0.0f <= vPro.y && vPro.y <= getHeight())
                {
                    for (NodeSetIterator it=mChildren.begin(); it!=mChildren.end(); ++it)
                    {
                        UIObject *child = dynamic_cast<UIObject*>(*it);
                        UIObject *obj = child->_detected(ray);
                        if (obj)
                        {
                            return obj;
                        }
                    }
                    mMouseOver = true;
                    return this;
                }
            }
        }
        return 0;
    }

    void UIObject::_onResized(const Vector2 &v)
    {
    }

    void UIObject::_onMouseOver(const MouseEvent &event)
    {
        mMouseOver = true;
    }

    void UIObject::_onMouseOut(const MouseEvent &event)
    {
        mMouseOver = false;
    }

    void UIObject::_onMouseMove(const MouseEvent &event)
    {
    }

    void UIObject::_onMouseWheel(const MouseEvent &event)
    {
    }

    void UIObject::_onMouseButtonUp(const MouseEvent &event)
    {
        mMouseButtonsDown = event.buttonsDown;
    }

    void UIObject::_onMouseButtonDown(const MouseEvent &event)
    {
        mMouseButtonsDown = event.buttonsDown;
    }

    void UIObject::_onMouseButtonDrag(const MouseEvent &event)
    {
        mMouseButtonsDown = event.buttonsDown;
    }

    void UIObject::_onMouseClicked(const MouseEvent &event)
    {
        mMouseButtonsDown = event.buttonsDown;
    }

    void UIObject::_onMouseDoubleClicked(const MouseEvent &event)
    {
        mMouseButtonsDown = event.buttonsDown;
    }

    void UIObject::_onKeyUp(const KeyboardEvent &event)
    {
    }

    void UIObject::_onKeyDown(const KeyboardEvent &event)
    {
    }

    void UIObject::_onCharacter(const uint32_t character)
    {
    }

    void UIObject::_onEnabled()
    {
    }

    void UIObject::_onDisabled()
    {
    }

    void UIObject::_onShown()
    {
    }

    void UIObject::_onHidden()
    {
    }

    void UIObject::_onActived()
    {
    }

    void UIObject::_onDeactived()
    {
    }
}
